package com.xinqi.modules.course.comment.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.xinqi.common.base.enums.YesNoNumberEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.response.R;
import com.xinqi.common.base.user.Account;
import com.xinqi.common.core.enums.ClassRoleEnum;
import com.xinqi.common.core.enums.CourseContentTypeEnum;
import com.xinqi.common.core.utils.MessageUtils;
import com.xinqi.common.mybatis.data.service.impl.BaseServiceImpl;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.modules.course.clazz.dto.rsp.ClassStudentResultDTO;
import com.xinqi.modules.course.clazz.service.ChatRemindSyncService;
import com.xinqi.modules.course.clazz.service.ClassStudentService;
import com.xinqi.modules.course.comment.convert.CommentConvert;
import com.xinqi.modules.course.comment.domain.CommentEntity;
import com.xinqi.modules.course.comment.domain.CommentGiveEntity;
import com.xinqi.modules.course.comment.dto.req.*;
import com.xinqi.modules.course.comment.dto.rsp.CommentDiscussResultDto;
import com.xinqi.modules.course.comment.dto.rsp.CommentResultDTO;
import com.xinqi.modules.course.comment.mapper.CommentMapper;
import com.xinqi.modules.course.comment.service.CommentGiveService;
import com.xinqi.modules.course.comment.service.CommentService;
import com.xinqi.modules.course.content.service.CourseContentService;
import com.xinqi.modules.discuss.discuss.client.CourseDiscussClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 课程栏目评论表服务层实现
 *
 * @author: yyzhen
 * @date: 2023/03/20
 */
@Slf4j
@Service("commentService")
@RequiredArgsConstructor
public class CommentServiceImpl extends BaseServiceImpl<CommentMapper, CommentEntity> implements CommentService {

    private final CommentConvert commentConvert;

    private final CommentGiveService commentGiveService;

    private final ClassStudentService classStudentService;

    private final CourseDiscussClient courseDiscussClient;

    @Lazy
    private final ChatRemindSyncService chatRemindSyncService;

    private final CourseContentService courseContentService;

    /**
     * 分页
     *
     * @Title:
     * @MethodName: page
     * [pageable, query]
     * @Return com.xinqi.common.base.response.PageInfo<com.xinqi.modules.sys.comment.dto.rsp.CommentResultDTO>
     * @Exception
     * @Description:
     * @author: yyzhen
     * @date: 2023/3/20 11:29
     */
    @Override
    @DS("slaver")
    public PageInfo<CommentResultDTO> page(Param pageable, CommentQueryDTO query) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(query.getContentId()), MessageUtils.message("course.comment.contentId.not.blank"));
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(query.getType()), MessageUtils.message("course.comment.type.not.blank"));
        if (Objects.equals(CourseContentTypeEnum.DISCUSS.getCode(), query.getType())) {
            CommentDiscussQueryDto dto = new CommentDiscussQueryDto();
            dto.setType(CourseContentTypeEnum.DISCUSS.getCode());
            dto.setContentId(query.getContentId());
            dto.setUserId(query.getOperationUserId());
            CommentDiscussResultDto result = this.baseMapper.selectCommentDiscuss(dto);
            //讨论时 -- 评论后方可查看他人评论
            if (Objects.nonNull(result) && Objects.equals(YesNoNumberEnum.YES.getCode(), result.getCommentView())) {
                if (Objects.equals(ClassRoleEnum.TEACHER.getCode(), result.getClassRole())
                        || Objects.equals(ClassRoleEnum.ASSISTANT.getCode(), result.getClassRole())) {
                    //助教、老师不需要
                } else {
                    if (Objects.nonNull(result.getTotal()) && result.getTotal() <= 0) {
                        return new PageInfo<>();
                    }
                }
            }
        }
        //排序
        if (CollectionUtils.isEmpty(pageable.getSorts())) {
            pageable.setSorts(new ArrayList<>());
        }
        if (Objects.isNull(query.getSuperPid())) {
            //默认查询顶层评论
            query.setSuperPid(0L);
            //评论--默认时间倒序，最新的评论在最前面
            pageable.getSorts().add("t1.create_time,desc");
        } else {
            //回复--默认时间正序，便于阅读
            pageable.getSorts().add("t1.create_time,asc");
        }
        IPage<CommentResultDTO> pageData = this.baseMapper.selectPage1(Pages.page(pageable), query);
        pageData.getRecords().forEach(records -> {
            if (records.getReply() > 0) {
                records.setList(this.baseMapper.selectSubComment(records.getId(), query.getOperationUserId()));
            }
        });
        return Pages.convert(pageData);
    }

    /**
     * 评论
     *
     * @Title:
     * @MethodName: insert
     * [dto]
     * @Return java.lang.Boolean
     * @Exception
     * @Description:
     * @author: yyzhen
     * @date: 2023/3/20 11:29
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommentResultDTO comment(CommentCreateDTO dto, Account user) {

        //校验为本班学生
        classStudentService.checkRole(dto.getClassId(), user.getId(), null);

        // 校验内容是否已被删除
        courseContentService.exitCourseContent(dto.getContentId(), dto.getType());

        dto.setUserId(user.getId());
        if (Objects.equals(CourseContentTypeEnum.DISCUSS.getCode(), dto.getType())) {
            //讨论时 -- 学生参与状态
            courseDiscussClient.participate(dto.getClassId(), dto.getContentId(), dto.getUserId());
        }

        CommentEntity entity = commentConvert.create(dto);
        this.save(entity);
        //新奇提醒机器人 -- 评论
        chatRemindSyncService.commentChatRemind(user, entity);
        return this.baseMapper.selectCommentById(entity.getId(), user.getId());
    }

    /**
     * 回复评论
     *
     * @Title:
     * @MethodName: reply
     * [dto]
     * @Return java.lang.Boolean
     * @Exception
     * @Description:
     * @author: yyzhen
     * @date: 2023/3/20 11:29
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommentResultDTO reply(CommentReplyDTO dto, Account user) {
        CommentEntity comments = Optional.ofNullable(this.getById(dto.getPid()))
                .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("course.comment.is.remove")));
        //校验为本班学生
        classStudentService.checkRole(comments.getClassId(), user.getId(), null);

        CommentEntity entity = commentConvert.reply(dto);
        entity.setType(comments.getType());
        entity.setContentId(comments.getContentId());
        entity.setClassId(comments.getClassId());
        entity.setUserId(user.getId());
        if (comments.getSuperPid() == 0) {
            entity.setSuperPid(comments.getId());
        } else {
            entity.setSuperPid(comments.getSuperPid());
        }
        entity.setTimes(comments.getTimes());
        entity.setToUserId(comments.getUserId());
        if (Objects.equals(CourseContentTypeEnum.DISCUSS.getCode(), comments.getType())) {
            //讨论时 -- 学生参与状态
            courseDiscussClient.participate(entity.getClassId(), entity.getContentId(), entity.getUserId());
        }
        this.save(entity);
        //新奇提醒机器人 -- 回复
        comments.setTitle(dto.getTitle());
        comments.setImages(dto.getImages());
        comments.setImageList(dto.getImageList());
        chatRemindSyncService.replyChatRemind(user, comments);
        return this.baseMapper.selectCommentById(entity.getId(), user.getId());
    }

    /**
     * 点赞 / 取消点赞
     *
     * @Title:
     * @MethodName: give
     * [dto]
     * @Return com.xinqi.common.base.response.R
     * @Exception
     * @Description:
     * @author: yyzhen
     * @date: 2023/3/26 17:02
     */
    @Override
    public R<Void> give(CommentGiveCreateDTO dto, Account user) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getComId()), MessageUtils.message("comment.comment.id.not.blank"));
        CommentEntity reply = Optional.ofNullable(this.getById(dto.getComId()))
                .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("course.comment.is.remove")));

        CommentGiveEntity giveEntity = commentGiveService.selectByComIdAndUserId(dto.getComId(), user.getId());
        if (Objects.isNull(giveEntity)) {
            //校验为本班学生
            classStudentService.checkRole(reply.getClassId(), user.getId(), null);
            //点赞
            CommentGiveEntity entity = new CommentGiveEntity();
            entity.setComId(dto.getComId());
            entity.setUserId(user.getId());
            commentGiveService.save(entity);
            //新奇提醒机器人 -- 点赞
            chatRemindSyncService.giveChatRemind(user, reply);
            return R.ok(MessageUtils.message("course.comment.message.give.success"));
        } else {
            //取消点赞
            commentGiveService.deleteById(giveEntity.getId());
            return R.ok(MessageUtils.message("course.comment.message.cancel.give.success"));
        }
    }


    /**
     * 删除评论
     *
     * @Title:
     * @MethodName: remove
     * [dto]
     * @Return java.lang.Boolean
     * @Exception
     * @Description:
     * @author: yyzhen
     * @date: 2023/3/20 11:29
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean remove(CommentDeleteDTO dto) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(dto.getId()), MessageUtils.message("comment.comment.id.not.blank"));
        //删除权限校验
        CommentEntity entity = this.checkRemove(dto.getId(), dto.getOperationUserId());

        if (Objects.equals(0L, entity.getSuperPid())) {
            //主评论：删除主评论及所有子评论
            LambdaQueryWrapper<CommentEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CommentEntity::getSuperPid, entity.getId());
            List<CommentEntity> list = this.baseMapper.selectList(queryWrapper);
            List<Long> ids = list.stream().map(CommentEntity::getId).collect(Collectors.toList());
            ids.add(dto.getId());
            //删除点赞
            LambdaUpdateWrapper<CommentGiveEntity> give = new LambdaUpdateWrapper<>();
            give.in(CommentGiveEntity::getComId, ids);
            commentGiveService.remove(give);
            //删除评论
            LambdaUpdateWrapper<CommentEntity> comment = new LambdaUpdateWrapper<>();
            comment.in(CommentEntity::getId, ids);

            return this.remove(comment);
        } else {
            //子评论：只删除单条子评论，子评论间的回复不受影响
            commentGiveService.deleteByComId(dto.getId());
            return this.deleteById(dto.getId());
        }
    }

    /**
     * 获取当前的总评论数与总点赞数
     *
     * @Title:
     * @MethodName: selectCountByTypeAndContentId
     * [type, contentId, times]
     * @Return java.util.Map<java.lang.String, java.lang.Integer>
     * @Exception
     * @Description:
     * @author: yyzhen
     * @date: 2023/4/24 21:23
     */
    @Override
    @DS("slaver")
    public Map<String, Integer> selectCountByTypeAndContentId(Integer type, Long contentId, Integer times) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(contentId), MessageUtils.message("course.comment.contentId.not.blank"));
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(type), MessageUtils.message("course.comment.type.not.blank"));
        return this.baseMapper.selectCountByTypeAndContentId(type, contentId, times);
    }

    /**
     * 删除权限校验
     *
     * @param id
     * @param userId
     */
    private CommentEntity checkRemove(Long id, Long userId) {
        CommentEntity entity = Optional.ofNullable(this.getById(id)).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("course.comment.is.remove")));
        ClassStudentResultDTO studentResult = classStudentService.checkRole(entity.getClassId(), userId, null);
        if (Objects.equals(ClassRoleEnum.STUDENT.getCode(), studentResult.getClassRole())) {
            //学生只可以删除自己的
            CommonErrors.BAD_REQUEST.check(Objects.equals(userId, entity.getCreateBy()), MessageUtils.message("course.discuss.message.fail"));
        } else if (Objects.equals(ClassRoleEnum.REPRESENTATIVE.getCode(), studentResult.getClassRole())) {
            //课代表（学生）只可以删除自己的
            CommonErrors.BAD_REQUEST.check(Objects.equals(userId, entity.getCreateBy()), MessageUtils.message("course.discuss.message.fail"));
        } else if (Objects.equals(ClassRoleEnum.ASSISTANT.getCode(), studentResult.getClassRole())) {
            //助教可以对班级所有人的进行删除
            CommonErrors.BAD_REQUEST.check(true, MessageUtils.message("course.discuss.message.fail"));
        } else if (Objects.equals(ClassRoleEnum.TEACHER.getCode(), studentResult.getClassRole())) {
            //老师可以对班级所有人的进行删除
            CommonErrors.BAD_REQUEST.check(true, MessageUtils.message("course.discuss.message.fail"));
        } else {
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("course.discuss.message.fail"));
        }
        return entity;
    }

}
